using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using OpenComposite.Base;
using OpenComposite.Base.Collections;
using OpenComposite.HumanActivity.Contracts.Participants;
using OpenComposite.EII.Designer.SCA;
using OpenComposite.Repository.Properties;

namespace OpenComposite.EII.Repository
{
	[RepositoryItem(ItemType.Component, "services", "service_id")]
	[DesignerAttribute(typeof(ServiceDesigner))]
	public class Service : RepositoryItemBaseEx
	{
		#region Initialization
		/// <summary>
		/// Initializes a new instance of the <see cref="Service"/> class.
		/// </summary>
		public Service()
			: base("service_id", "service_nm", "service_desc", "service_ntext", Resources.sNewService)
		{
			_symbol = null;
		}
		/// <summary>
		/// Initializes a new instance of the <see cref="Service"/> class.
		/// </summary>
		/// <param name="bCreateNew">if set to <c>true</c> [b create new].</param>
		public Service(bool bCreateNew)
			: this()
		{
			if ( bCreateNew )
				this.CreateNew();
		}
		/// <summary>
		/// Initializes a new instance of the <see cref="Service"/> class.
		/// </summary>
		/// <param name="id">The id.</param>
		public Service(int id)
			: this()
		{
			this.Load(id);
		}
		#endregion

		#region Properties

		/// <summary>
		/// Gets or sets the type.
		/// </summary>
		/// <value>The type.</value>
		public ServiceType Type
		{
			get { return (ServiceType)getValue("service_type", ServiceType.Service); }
			set { setValue("Type", "service_type", value); }
		}

		/// <summary>
		/// Gets the type of the repository item.
		/// </summary>
		/// <value>The type of the repository item.</value>
		public override ItemType RepositoryItemType
		{
			get { return ItemType.Component; }
		}
		/// <summary>
		/// Gets the name of the repository item type.
		/// </summary>
		/// <value>The name of the repository item type.</value>
		public override string RepositoryItemTypeName
		{
			get { return Resources.sService; }
		}
		/// <summary>
		/// Gets the repository item type description.
		/// </summary>
		/// <value>The repository item type description.</value>
		public override string RepositoryItemTypeDescription
		{
			get { return ""; }
		}

		/// <summary>
		/// Gets the image key.
		/// </summary>
		/// <value>The image key.</value>
		public override string ImageKey
		{
			get
			{
				switch ( this.Type ) {
					case ServiceType.HumanTask:
						return "ha_component";
					case ServiceType.SQLCommands:
						return "sql_component";
					case ServiceType.UserInterface:
						return "ui_component";
					case ServiceType.Orchestration:
						return "workflow";
					default:
						return "service";
				}
			}
		}
		/// <summary>
		/// Gets the selected image key.
		/// </summary>
		/// <value>The selected image key.</value>
		public override string SelectedImageKey
		{
			get { return this.ImageKey; }
		}
		/// <summary>
		/// Gets the image.
		/// </summary>
		/// <value>The image.</value>
		public override Image Image
		{
			get
			{
				switch ( this.Type ) {
					case ServiceType.HumanTask:
						return Resources.png_user;
					case ServiceType.SQLCommands:
						return Resources.ico_db.ToBitmap();
					case ServiceType.UserInterface:
						return Resources.png_form;
					case ServiceType.Orchestration:
						return Resources.ico_workflow.ToBitmap();
					default:
						return Resources.service;
				}
			}
		}
		/// <summary>
		/// Gets the selected image.
		/// </summary>
		/// <value>The selected image.</value>
		public override Image SelectedImage
		{
			get { return this.Image; }
		}

		/// <summary>
		/// Gets the name of the table.
		/// </summary>
		/// <value>The name of the table.</value>
		public override string TableName
		{
			get { return "services"; }
		}
		private static List<ItemType> _LISTALLOWED =
			new List<ItemType>(new ItemType[] { ItemType.GenericFolder, ItemType.Operation });
		/// <summary>
		/// Gets the allowed child types.
		/// </summary>
		/// <value>The allowed child types.</value>
		public override List<ItemType> AllowedChildTypes
		{
			get { return _LISTALLOWED; }
		}

		private ServiceComponentSymbol _symbol;
		/// <summary>
		/// Gets or sets the symbol.
		/// </summary>
		/// <value>The symbol.</value>
		public ServiceComponentSymbol Symbol
		{
			get { return _symbol; }
			set { _symbol = value; }
		}

		private ServiceModuleSymbol _symbolModule;
		/// <summary>
		/// Gets or sets the module symbol.
		/// </summary>
		/// <value>The module symbol.</value>
		public ServiceModuleSymbol ModuleSymbol
		{
			get { return _symbolModule; }
			set { _symbolModule = value; }
		}

		private XmlDocument _xdWSConnections = null;
		/// <summary>
		/// Gets or sets the web service connections.
		/// </summary>
		/// <value>The web service connections.</value>
		public XmlDocument WebServiceConnections
		{
			get
			{
				if ( _xdWSConnections == null ) {
					_xdWSConnections = getXmlDocument("service_ws_connections");
				}
				return _xdWSConnections;
			}
			set
			{
				_xdWSConnections = value;
				setXmlDocument("WebServiceConnections", "service_ws_connections", value);
			}
		}

		//private XmlDocument _xdProperties = null;
		//public XmlDocument Properties
		//{
		//    get {
		//        if ( _xdProperties == null ) {
		//            _xdProperties = getXmlDocument("service_properties");
		//        }
		//        return _xdProperties;
		//    }
		//    set {
		//        _xdProperties = value;
		//        setXmlDocument("Properties", "service_properties", value);
		//    }
		//}

		private ComponentProperties _properties = null;
		/// <summary>
		/// Gets the extended properties.
		/// </summary>
		/// <value>The extended properties.</value>
		public ComponentProperties ExtendedProperties
		{
			get
			{
				if ( _properties == null ) {
					_properties = getXmlSerializedObject<ComponentProperties>("service_properties");
					if ( _properties == null )
						_properties = new ComponentProperties();
				}
				return _properties;
			}
		}

		/// <summary>
		/// Gets or sets the human activity ID.
		/// </summary>
		/// <value>The human activity ID.</value>
		public int HumanActivityID
		{
			get { return getInt("service_hact_id", -1); }
			set { setValue("HumanActivityID", "service_hact_id", value); }
		}
		/// <summary>
		/// Gets or sets the human activity.
		/// </summary>
		/// <value>The human activity.</value>
		public HumanActivity HumanActivity
		{
			get
			{
				if ( this.HumanActivityID > 0 )
					return this.RepositoryService.GetItem(ItemType.HumanActivity, this.HumanActivityID, false) as HumanActivity;
				else
					return null;
			}
			set { this.HumanActivityID = ( value == null ? -1 : value.ID ); }
		}


		#endregion

		#region Methods

		/// <summary>
		/// Gets the interfaces.
		/// </summary>
		/// <returns></returns>
		public BindingListEx<GenericFolder> GetInterfaces()
		{
			return Global.Data.GetRepositoryHierarchyChildRepositoryList<GenericFolder>(
					this.RepositoryItemType, this.ID, ItemType.GenericFolder);
		}

		/// <summary>
		/// Gets the icon.
		/// </summary>
		/// <returns></returns>
		public override Icon GetIcon()
		{
			Bitmap bmp = new Bitmap(this.Image);
			bmp.MakeTransparent(Color.Magenta);
			return Icon.FromHandle(bmp.GetHicon());
		}

		/// <summary>
		/// Saves this instance.
		/// </summary>
		/// <returns></returns>
		public override bool Save()
		{
			if ( _properties != null )
				setXmlSerializedObject("ExtendedProperties", "service_properties", _properties);

			bool ok = base.Save();
			if ( ok ) {
				HumanActivity ha = this.HumanActivity;
				if ( this.Type == ServiceType.HumanTask && ha != null ) {
					Global.Data.SetServiceWebService(this.ID, ha.WebServiceID);
				}
			}
			return ok;
		}

		/// <summary>
		/// Copies this instance.
		/// </summary>
		/// <param name="deep"><c>true</c> to recursively copy the item and all subitems;
		/// <c>false</c> to copy only the item itself.</param>
		/// <returns>The copied item.</returns>
		public override IRepositoryItem Copy(bool deep)
		{
			Service copy = new Service(true);
			copy.InitializeServiceProvider(this);
			this.CopyDataRowToTarget(copy);
			return copy;
		}
		#endregion Methods

		#region Enum: ServiceType
		public enum ServiceType
		{
			Service = 0,
			Category,
			Orchestration,
			HumanTask,
			SQLCommands,
			Selector,
			Rule,
			UserInterface
		}
		#endregion
	}

	#region Class: Component Properties
	[Serializable]
	[XmlType(Namespace = "http://www.OpenComposite.com/Designer")]
	[XmlRoot(Namespace = "http://www.OpenComposite.com/Designer")]
	public class ComponentProperties
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="ComponentProperties"/> class.
		/// </summary>
		public ComponentProperties()
		{
			_haprops = null;
			_uiprops = null;
		}
		private HumanComponentProperties _haprops;
		/// <summary>
		/// Gets or sets the human component properties.
		/// </summary>
		/// <value>The human component properties.</value>
		public HumanComponentProperties HumanComponentProperties
		{
			get
			{
				if ( _haprops == null )
					_haprops = new HumanComponentProperties();
				return _haprops;
			}
			set { _haprops = value; }
		}

		private UIComponentProperties _uiprops;
		/// <summary>
		/// Gets or sets the UI component properties.
		/// </summary>
		/// <value>The UI component properties.</value>
		public UIComponentProperties UIComponentProperties
		{
			get
			{
				if ( _uiprops == null )
					_uiprops = new UIComponentProperties();
				return _uiprops;
			}
			set { _uiprops = value; }
		}
	}
	#endregion

	#region Human Task Component Property Classes

	#region Class: HumanComponentProperties
	[Serializable]
	[XmlType(Namespace = "http://www.OpenComposite.com/Designer")]
	[XmlRoot(Namespace = "http://www.OpenComposite.com/Designer")]
	[TypeConverter(typeof(ExpandableObjectConverter))]
	public class HumanComponentProperties
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="HumanComponentProperties"/> class.
		/// </summary>
		public HumanComponentProperties()
		{
			this.ProcessName = "";
			this.ActivityName = "";
			this.Subject = "";

			this.AssemblyName = "";
			this.FormName = "";

			this.Participants = new List<HumanComponentParticipant>();
		}

		/// <summary>
		/// Gets or sets the participants.
		/// </summary>
		/// <value>The participants.</value>
		public List<HumanComponentParticipant> Participants { get; set; }

		/// <summary>
		/// Gets or sets the name of the process.
		/// </summary>
		/// <value>The name of the process.</value>
		public string ProcessName { get; set; }
		/// <summary>
		/// Gets or sets the name of the activity.
		/// </summary>
		/// <value>The name of the activity.</value>
		public string ActivityName { get; set; }
		/// <summary>
		/// Gets or sets the subject.
		/// </summary>
		/// <value>The subject.</value>
		public string Subject { get; set; }

		/// <summary>
		/// Gets or sets the name of the assembly.
		/// </summary>
		/// <value>The name of the assembly.</value>
		public string AssemblyName { get; set; }
		/// <summary>
		/// Gets or sets the name of the form.
		/// </summary>
		/// <value>The name of the form.</value>
		public string FormName { get; set; }

		/// <summary>
		/// Reads the XML document.
		/// </summary>
		/// <param name="xd">The xd.</param>
		public void ReadXmlDocument(XmlDocument xd)
		{
			HumanComponentProperties props = null;
			if ( xd != null && xd.DocumentElement != null ) {
				using ( StringReader sr = new StringReader(xd.DocumentElement.OuterXml) ) {
					XmlSerializer xs = new XmlSerializer(typeof(HumanComponentProperties));
					props = xs.Deserialize(sr) as HumanComponentProperties;
				}
			}
			if ( props != null ) {
				this.Participants.Clear();
				this.Participants.AddRange(props.Participants);
				this.ProcessName = props.ProcessName;
				this.ActivityName = props.ActivityName;
				this.Subject = props.Subject;
				this.AssemblyName = props.AssemblyName;
				this.FormName = props.FormName;
			}
		}
		/// <summary>
		/// Writes the XML document.
		/// </summary>
		/// <returns></returns>
		public XmlDocument WriteXmlDocument()
		{
			XmlDocument xd = new XmlDocument();
			using ( StringWriter sw = new StringWriter() ) {
				XmlSerializer xs = new XmlSerializer(typeof(HumanComponentProperties));
				xs.Serialize(sw, this);
				xd.LoadXml(sw.ToString());
			}
			return xd;
		}
	}
	#endregion
	#region Class: HumanComponentParticipant
	[Serializable]
	[XmlType(Namespace = "http://www.OpenComposite.com/Designer")]
	public class HumanComponentParticipant
	{
		#region Initialization
		private HumanComponentParticipant()
		{
			this.ID = -1;
			this.Display = "";
			this.ParticipationType = ParticipationType.IncludedParticipant;
			this.Type = ParticipantType.None;
			this.Additional1 = null;
			this.Additional2 = null;
		}
		/// <summary>
		/// Initializes a new instance of the <see cref="HumanComponentParticipant"/> class.
		/// </summary>
		/// <param name="part">The part.</param>
		public HumanComponentParticipant(IParticipant part)
		{
			this.Type = ParticipantType.None;
			if ( part is EmailParticipant ) {
				this.Type = ParticipantType.EmailParticipant;
				this.Additional1 = ( (EmailParticipant)part ).EmailAddress;
				this.Additional2 = ( (EmailParticipant)part ).Name;
			} else if ( part is PropertyParticipant ) {
				this.Type = ParticipantType.PropertyParticipant;
				this.Additional1 = ( (PropertyParticipant)part ).Property;
			} else if ( part is Organization ) {
				this.Type = ParticipantType.Organization;
			} else if ( part is OrganizationalUnit ) {
				this.Type = ParticipantType.OrganizationUnit;
			} else if ( part is RepositoryBusinessRule ) {
				this.Type = ParticipantType.ParticipantRule;
				//} else if ( part is PartnerRole ) {
				//    this.Type = ParticipantType.PartnerRole;
				//    //this.Additional = ( (PartnerRole)part ).Guid.ToString();
				//} else if ( part is PartnerRule ) {
				//    this.Type = ParticipantType.PartnerRule;
				//    //this.Additional = ( (PartnerRule)part ).Vocabulary;
			} else if ( part is Role ) {
				this.Type = ParticipantType.Role;
			} else if ( part is User ) {
				this.Type = ParticipantType.User;
			}
			this.Display = part.Display;
			this.ID = part.ID;
		}
		#endregion

		#region Properties
		/// <summary>
		/// Gets or sets the display.
		/// </summary>
		/// <value>The display.</value>
		[System.Xml.Serialization.XmlAttribute]
		public string Display { get; set; }

		/// <summary>
		/// Gets or sets the ID.
		/// </summary>
		/// <value>The ID.</value>
		[System.Xml.Serialization.XmlAttribute]
		public int ID { get; set; }

		/// <summary>
		/// Gets or sets the type.
		/// </summary>
		/// <value>The type.</value>
		[System.Xml.Serialization.XmlAttribute]
		public ParticipantType Type { get; set; }

		/// <summary>
		/// Gets or sets the type of the participation.
		/// </summary>
		/// <value>The type of the participation.</value>
		[System.Xml.Serialization.XmlAttribute]
		public ParticipationType ParticipationType { get; set; }

		/// <summary>
		/// Gets or sets the additional1.
		/// </summary>
		/// <value>The additional1.</value>
		[System.Xml.Serialization.XmlAttribute]
		public string Additional1 { get; set; }

		/// <summary>
		/// Gets or sets the additional2.
		/// </summary>
		/// <value>The additional2.</value>
		[System.Xml.Serialization.XmlAttribute]
		public string Additional2 { get; set; }
		#endregion

		#region Methods
		/// <summary>
		/// Returns a <see cref="System.String"/> that represents this instance.
		/// </summary>
		/// <returns>
		/// A <see cref="System.String"/> that represents this instance.
		/// </returns>
		public override string ToString()
		{
			return this.Display;
		}

		/// <summary>
		/// Gets the IParticipant.
		/// </summary>
		/// <returns></returns>
		public IParticipant GetIParticipant()
		{
			IParticipant part;
			switch ( this.Type ) {
				case ParticipantType.EmailParticipant:
					part = new EmailParticipant();
					( (EmailParticipant)part ).EmailAddress = this.Additional1;
					( (EmailParticipant)part ).Name = this.Additional2;
					break;
				case ParticipantType.PropertyParticipant:
					part = new PropertyParticipant();
					( (PropertyParticipant)part ).Property = this.Additional1;
					break;
				case ParticipantType.Organization:
					part = Global.Repository.GetItem<Organization>(this.ID);
					break;
				case ParticipantType.OrganizationUnit:
					part = Global.Repository.GetItem<OrganizationalUnit>(this.ID);
					break;
				case ParticipantType.ParticipantRule:
					part = Global.Repository.GetItem<RepositoryBusinessRule>(this.ID);
					break;
				case ParticipantType.PartnerRole:
					part = null;
					break;
				case ParticipantType.PartnerRule:
					part = null;
					break;
				case ParticipantType.Role:
					part = Global.Repository.GetItem<Role>(this.ID);
					break;
				case ParticipantType.User:
					part = Global.Repository.GetItem<User>(this.ID);
					break;
				default:
					part = null;
					break;
			}
			return part;
		}
		#endregion
	}
	#endregion

	#endregion

	#region UI Component Property Class

	#region Class: UIComponentProperties
	[Serializable]
	[XmlType(Namespace = "http://www.OpenComposite.com/Designer")]
	[XmlRoot(Namespace = "http://www.OpenComposite.com/Designer")]
	public class UIComponentProperties
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="UIComponentProperties"/> class.
		/// </summary>
		public UIComponentProperties()
		{
		}

		private string _pathProject;
		/// <summary>
		/// Gets or sets the project path.
		/// </summary>
		/// <value>The project path.</value>
		public string ProjectPath
		{
			get { return _pathProject; }
			set { _pathProject = value; }
		}

	}
	#endregion

	#endregion

	#region Internal Class ServiceDesigner : RepositoryItemDesigner
	internal class ServiceDesigner : RepositoryItemDesigner
	{
		/// <summary>
		/// Gets the type of the designer control item.
		/// </summary>
		/// <returns></returns>
		public override ItemType GetDesignerControlItemType()
		{
			Service svc = this.Component as Service;
			if ( svc == null ) return base.GetDesignerControlItemType();
			ItemType type = svc.RepositoryItemType;
			switch ( svc.Type ) {
				case Service.ServiceType.Service:
					type = ItemType.Component;
					break;
				case Service.ServiceType.Orchestration:
					type = ItemType.OrchestrationComponent;
					break;
				case Service.ServiceType.HumanTask:
					type = ItemType.HumanComponent;
					break;
				case Service.ServiceType.UserInterface:
					type = ItemType.UIComponent;
					break;
				case Service.ServiceType.SQLCommands:
					type = ItemType.SQLComponent;
					break;
				case Service.ServiceType.Selector:
					type = ItemType.Selector;
					break;
				case Service.ServiceType.Rule:
					type = ItemType.RuleComponent;
					break;
			}
			return type;
		}
	}
	#endregion
}